/**
 * Software License, Version 1.0
 *
 * Copyright 2003 The Trustees of Indiana University.  All rights reserved.
 *
 *
 *Redistribution and use in source and binary forms, with or without
 *modification, are permitted provided that the following conditions are met:
 *
 *1) All redistributions of source code must retain the above copyright notice,
 * the list of authors in the original source code, this list of conditions and
 * the disclaimer listed in this license;
 *2) All redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the disclaimer listed in this license in
 * the documentation and/or other materials provided with the distribution;
 *3) Any documentation included with all redistributions must include the
 * following acknowledgement:
 *
 *"This product includes software developed by the Community Grids Lab. For
 * further information contact the Community Grids Lab at
 * http://communitygrids.iu.edu/."
 *
 * Alternatively, this acknowledgement may appear in the software itself, and
 * wherever such third-party acknowledgments normally appear.
 *
 *4) The name Indiana University or Community Grids Lab or NaradaBrokering,
 * shall not be used to endorse or promote products derived from this software
 * without prior written permission from Indiana University.  For written
 * permission, please contact the Advanced Research and Technology Institute
 * ("ARTI") at 351 West 10th Street, Indianapolis, Indiana 46202.
 *5) Products derived from this software may not be called NaradaBrokering,
 * nor may Indiana University or Community Grids Lab or NaradaBrokering appear
 * in their name, without prior written permission of ARTI.
 *
 *
 * Indiana University provides no reassurances that the source code provided
 * does not infringe the patent or any other intellectual property rights of
 * any other entity.  Indiana University disclaims any liability to any
 * recipient for claims brought by any other entity based on infringement of
 * intellectual property rights or otherwise.
 *
 *LICENSEE UNDERSTANDS THAT SOFTWARE IS PROVIDED "AS IS" FOR WHICH NO
 *WARRANTIES AS TO CAPABILITIES OR ACCURACY ARE MADE. INDIANA UNIVERSITY GIVES
 *NO WARRANTIES AND MAKES NO REPRESENTATION THAT SOFTWARE IS FREE OF
 *INFRINGEMENT OF THIRD PARTY PATENT, COPYRIGHT, OR OTHER PROPRIETARY RIGHTS.
 *INDIANA UNIVERSITY MAKES NO WARRANTIES THAT SOFTWARE IS FREE FROM "BUGS",
 *"VIRUSES", "TROJAN HORSES", "TRAP DOORS", "WORMS", OR OTHER HARMFUL CODE.
 *LICENSEE ASSUMES THE ENTIRE RISK AS TO THE PERFORMANCE OF SOFTWARE AND/OR
 *ASSOCIATED MATERIALS, AND TO THE PERFORMANCE AND VALIDITY OF INFORMATION
 *GENERATED USING SOFTWARE.
 */

package cgl.narada.service.tds;

/**
 *
 * @author Hasan Bulut  - hbulut@indiana.edu
 * Community Grids Lab., Indiana University
 * @version 1.0
 */

import cgl.narada.service.qos.QosEvent;
import cgl.narada.service.qos.impl.QosServiceImpl;
import cgl.narada.service.timer.ClockI;
import cgl.narada.service.timer.HRClock;

public class TDSHandler
    extends Thread {
  //~ Instance fields ----------------------------------------------------------

  protected TDServiceImpl tdServiceImpl;
  protected QosServiceImpl myQoSService;
  protected TDSBuffer tdsBuffer = new TDSBuffer();
  protected ClockI hrtimer;

  protected long firstEventTimestamp = 0;
  protected long firstEventSystemTimestamp = 0;
  protected long lastEventTimestamp = 0;
  protected long delta = 0; // firstEventSystemTimestamp - firstEventTimestamp

  protected boolean running = true;
  private long duration = 0;
  protected int threadno = 3;
  protected boolean ready = false;
  protected int timeslice = 1;
  protected int delay = 0;
  protected int counter = 0;
  protected int[] thFlag = {0, 0, 0};
  private String moduleName = "TDSHandler: ";
  private boolean debug = false;
  protected boolean isPaused = false;
  protected long pauseStartTime	= 0;
  protected long pauseEndTime = 0;
  protected int speed = 5;
  protected int	speedup = 0;
  
  protected EventReleaser evtRel1 = null;
  protected EventReleaser evtRel2 = null;
  protected EventReleaser evtRel3 = null;

  public TDSHandler(QosServiceImpl qosServiceImpl) {
    myQoSService = qosServiceImpl;
  }

  public void onTimeSpacedEvent(QosEvent qosEvent) {
    myQoSService.onTimeSpacedDelivery(qosEvent);
  }

  public void toTimeSpaceBuffer(QosEvent qosEvent) {
    tdsBuffer.putEvent(qosEvent);
    System.out.println(moduleName + "Buffer size = " + tdsBuffer.size() );
  }

  public void run() {
    hrtimer = HRClock.getClock();
    EventReleaser evtRel1 = new EventReleaser(0);
    EventReleaser evtRel2 = new EventReleaser(1);
    EventReleaser evtRel3 = new EventReleaser(2);
    while (tdsBuffer.size() < 80) {
      hrtimer.sleep(100);
    }
    evtRel1.start();
    evtRel2.start();
    evtRel3.start();
  }

  public void terminateService() {
    while (tdsBuffer.size() > 0) {
      try {
        sleep(1000);
        System.out.println("waiting for all events to be released");
      }
      catch (InterruptedException ex) {
      }
    }
    running = false;
  }

  public void shutDownService() {
    running = false;
  }

  public void pauseService() {
    System.out.println("Pause Service is called");
    isPaused = true;
    pauseStartTime = hrtimer.getTimeMilliseconds();
  }
  

  
  public void replayService() {
    System.out.println("ReplayService is called");
    pauseEndTime = hrtimer.getTimeMilliseconds();
    if (pauseStartTime != 0) {
      delta = delta + (int) (pauseEndTime - pauseStartTime);
    }
    isPaused = false;
    System.out.println("pauseEndTime:" + pauseEndTime + " pauseStartTime:"
		       + pauseStartTime);
    pauseStartTime = 0;
    pauseEndTime = 0;
  }

  
  class EventReleaser  extends Thread {
    private long eventTimestamp = 0;
    private long timestampOffset = 0;
    private long tempTimestamp = 0;
    private int threadID = 0;
    private int threadNum = 3;
    private long localTimeMillis = 0;
    boolean isRun = true;
    boolean isReady = false;
    long nextTS = 0;
    long TSslice = 0;

    public EventReleaser(int id) {
      threadID = id;
    }

    public boolean allReady() {
      if ( ( (thFlag[0] * thFlag[1] * thFlag[2]) == 1) &&
          (tdsBuffer.size() >= 80)) {
        return true;
      }
      else
        return false;
    }

    public void run() {
      System.out.println("starting TDServices");
      isRun = true;
      localTimeMillis = hrtimer.getTimeMilliseconds();
      while (isRun) {
        hrtimer.sleep(1); // sleep for 1 msec
        localTimeMillis = hrtimer.getTimeMilliseconds();
        if ( (localTimeMillis % threadNum) == threadID) {
          isRun = false;
          thFlag[threadID] = 1;
        }
      }
      while (!allReady()) {
        hrtimer.sleep(timeslice);
      }

      if (firstEventSystemTimestamp == 0) {
        //firstEventTimestamp
        firstEventTimestamp = tdsBuffer.getTimestamp();
        firstEventSystemTimestamp = hrtimer.getTimeMilliseconds();
        delta = firstEventSystemTimestamp - firstEventTimestamp;
        // release event
        onTimeSpacedEvent( (QosEvent) tdsBuffer.removeFirst());
        lastEventTimestamp = firstEventTimestamp;
//        System.out.println("delta:"+delta);
        hrtimer.sleep(timeslice);
      }
      while (running) {
        tempTimestamp = hrtimer.getTimeMilliseconds();
        eventTimestamp = tdsBuffer.getTimestamp();
        if (tdsBuffer.size() >= 1) {
          eventTimestamp = eventTimestamp + delta;
          TSslice = tempTimestamp - eventTimestamp;
          if (eventTimestamp <= lastEventTimestamp) {
            onTimeSpacedEvent( (QosEvent) tdsBuffer.removeFirst());
          }
          else if (TSslice > (long) timeslice) {
            lastEventTimestamp = eventTimestamp;
            onTimeSpacedEvent( (QosEvent) tdsBuffer.removeFirst());
          }
          else {
            hrtimer.sleep(timeslice);
          }
        }
        else {
          hrtimer.sleep(timeslice);
        }
      }
      System.out.println("TDService stopped");
    }
  }
}
